#include "Helper.h"

#include <filesystem>
#include <iostream>

#include "rocksdb/db.h"
#include "rocksdb/options.h"


using namespace std;
using namespace rocksdb;

bool Helper::dbPathExist(const std::string & dbname){
    return std::filesystem::exists(dbname);
}
std::shared_ptr<rocksdb::DB> Helper::createDb(const std::string & name){
    rocksdb::DB* rdb;

    rocksdb::Options options;
    options.create_if_missing = true;

    rocksdb::Status s = rocksdb::DB::Open(options, name, &rdb);
    if(!s.ok()) std::cout << s.ToString() << std::endl;
    assert(s.ok());

    std::shared_ptr<rocksdb::DB> db;
    if(s.ok()){
        db.reset(rdb, [&name](rocksdb::DB *db){
                std::cout << "delete rocksdb db:" << name  << std::endl;
                delete (rocksdb::DB*)db;
            }
        );
    }
    return db;
}

std::shared_ptr<rocksdb::DB> Helper::createDbCfs(const std::string & dbname, std::vector<ColumnFamilyHandle *> & handles){
    if(!dbPathExist(dbname)){
        //create default db
        createDb(dbname);
    }

    //list ColumnFamilies
    std::vector<std::string> cfs;
    DBOptions dbOptions;
    dbOptions.create_if_missing = true;
    dbOptions.create_missing_column_families = true;

    auto s = rocksdb::DB::ListColumnFamilies(dbOptions, dbname, &cfs);
    if(!s.ok()) std::cerr << s.ToString() << std::endl;
    assert(s.ok());

    // create ColumnFamilyDescriptors for open multi-cfs
    std::vector<ColumnFamilyDescriptor> column_families;
    for(auto && cfname : cfs){
        column_families.push_back(
            ColumnFamilyDescriptor(cfname, ColumnFamilyOptions()));
    }

    //open it for all column families
    rocksdb::DB* rdb;

    rocksdb::Options options;
    options.create_if_missing = true;

    s = rocksdb::DB::Open(options,dbname, column_families, &handles, &rdb);
    if(!s.ok()) std::cout << s.ToString() << std::endl;
    assert(s.ok());
    
    // return the db 's shared_ptr 
    std::shared_ptr<rocksdb::DB> db;
    if(s.ok()){
        db.reset(rdb, [&dbname](rocksdb::DB *db){
                std::cout << "delete rocksdb db:" << dbname  << std::endl;
                delete (rocksdb::DB*)db;
            }
        );
    }
    return db;
}
